package com.marinesky.mstools.file;
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/
//          佛曰:
//                  写字楼里写字间，写字间里程序员；
//                  程序人员写程序，又拿程序换酒钱。
//                  酒醒只在网上坐，酒醉还来网下眠；
//                  酒醉酒醒日复日，网上网下年复年。
//                  但愿老死电脑间，不愿鞠躬老板前；
//                  奔驰宝马贵者趣，公交自行程序员。
//                  别人笑我忒疯癫，我笑自己命太贱；
//                  不见满街漂亮妹，哪个归得程序员？

import com.marinesky.mstools.common.Constant;
import com.marinesky.mstools.date.DateUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.util.zip.*;

/**
 * ================================================
 * ❶.Java原生的压缩文件方法(包括zip,unzip,gzip,unGzip)
 * ❷.Java1.7版本以上压缩中文名文件不会乱码,其它版本存在乱码
 * ❸.zip是可以压缩多个文件,gzip是压缩单个文件
 * ================================================
 */
public class CompressFile {



    /**
     * 压缩文件或文件夹
     * @param file  --输入文件或文件夹
     * @param zipFile  --输出压缩文件
     */
    public static void zipFile(File file,File zipFile){
        try{
            if(file==null || !file.exists() ){
                throw new FileNotFoundException("the file is null or not exists !");
            }
            //记录开始压缩时间
            long beginMillis=System.currentTimeMillis();
            //压缩输出流,并设置编码为当前系统编码,防止乱码
            ZipOutputStream zipOutputStream=new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName(Constant.SystemsPlatform.DEFAULT_ENCODING));
            //压缩文件过程,具体实现
            zipFile(zipOutputStream,file,null);
            //记录结束压缩时间
            long endMillis=System.currentTimeMillis();
            //转换中文注释乱码问题
            String comment="压缩总共花费时间:"+ DateUtil.millisToSimple(endMillis - beginMillis);
            zipOutputStream.setComment(comment);
            zipOutputStream.closeEntry();
            zipOutputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 压缩文件具体过程及算法
     * @param zipOutputStream
     * @param file
     * @param parentPath
     */
    private static void zipFile(ZipOutputStream zipOutputStream,File file,String parentPath){
        try{
            if(file.isDirectory()){
                String curPath="";
                if(parentPath==null){
                    curPath=file.getName()+File.separator;
                }
                else{
                    curPath=parentPath+file.getName()+File.separator;
                }
                zipOutputStream.putNextEntry(new ZipEntry(curPath+"/"));
                File[] subFiles=file.listFiles();
                for(File subFile:subFiles){
                    zipFile(zipOutputStream,subFile,curPath);
                }
            }
            else{
                String curPath="";
                if(parentPath==null){
                    curPath=file.getName();
                }
                else{
                    curPath=parentPath+file.getName();
                }
                zipOutputStream.putNextEntry(new ZipEntry(curPath));
                FileInputStream stream = new FileInputStream(file);
                byte[] b = new byte[1<<10];
                int n;
                while ((n = stream.read(b)) != -1){
                    zipOutputStream.write(b, 0, n);
                }
                stream.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 压缩文件或文件夹
     * @param file --输入文件或文件夹
     * @param zipFilePath --输出压缩文件路径
     */
    public static void zipFile(File file,String zipFilePath){
        File zipFile=FileUtil.getFile(zipFilePath);
        zipFile(file, zipFile);
    }

    /**
     * 压缩文件或文件夹
     * @param filePath --输入文件或文件夹路径
     * @param zipFilePath --输出压缩文件路径
     */
    public static void zipFile(String filePath,String zipFilePath){
        File file=FileUtil.getFile(filePath);
        File zipFile=FileUtil.getFile(zipFilePath);
        zipFile(file,zipFile);
    }

    /**
     * 压缩文件或文件夹,默认压缩文件名为文件名加后缀.zip或文件夹名加zip
     * 存放在该文件或文件夹的目录
     * 压缩的文件夹与原始结构保持一致
     * java7版本不会存在中文乱码的情况
     * @param file  --输入文件或文件夹
     *
     */
    public static void zipFile(File file){

        try{
            if(file==null || !file.exists() ){
                throw new FileNotFoundException("the inFile is null or not exists !");
            }
            //记录开始压缩时间
            long beginMillis=System.currentTimeMillis();
            //获取文件或文件夹的名称
            String inFileName= FileUtil.getFileName(file);
            //获取文件或文件夹所在的路径
            String dirPath=file.getParentFile().getAbsolutePath();
            //生成ZIP文件
            String filePath=dirPath+File.separator+inFileName+ Constant.File.FILE_DOT+Constant.File.EXTENSION_ZIP;
            //压缩文件
            File zipFile=FileUtil.getFile(filePath);
            zipFile(file,zipFile);
        }catch (Exception e){
            e.printStackTrace();
        }

    }




    /**
     * 压缩文件或文件夹,默认压缩文件名为文件名加后缀.zip或文件夹名加zip
     * 存放在该文件或文件夹的目录
     * 压缩的文件夹与原始结构保持一致
     * java7版本不会存在中文乱码的情况
     * @param filesPath  --输入文件或文件夹路径
     *
     */
    public static void zipFile(String filesPath){
        File file=FileUtil.getFile(filesPath);
        zipFile(file);
    }


    /**
     * 压缩多个文件
     * @param files  --多个文件
     * @param zipFile  --压缩后文件
     */
    public static void zipFiles(File[] files,File zipFile){
        try{
            //记录开始压缩时间
            long beginMillis=System.currentTimeMillis();
            //压缩输出流,并设置编码为当前系统编码,防止乱码
            ZipOutputStream zipOutputStream=new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName(Constant.SystemsPlatform.DEFAULT_ENCODING));
            //压缩文件过程,具体实现
            for (File file:files){
                zipFile(zipOutputStream,file,null);
            }
            //记录结束压缩时间
            long endMillis=System.currentTimeMillis();
            //转换中文注释乱码问题
            String comment="压缩总共花费时间:"+ DateUtil.millisToSimple(endMillis - beginMillis);
            zipOutputStream.setComment(comment);
            zipOutputStream.closeEntry();
            zipOutputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }



    /**
     * 解压文件到某个位置(压缩中的文件与原来目录结构一致)
     * @param zipFile  --压缩文件
     * @param outDir  --解压目录
     */
    public static void unZipFile(File zipFile,File outDir){
        try{
            if(zipFile==null || !zipFile.exists() ){
                throw new FileNotFoundException("the zipFile is null or not exists !");
            }
            //记录开始解压开始时间
            long beginMillis=System.currentTimeMillis();
            //压缩文件输入流,并设置编码为当前系统编码,防止乱码

            ZipInputStream zipInputStream=new ZipInputStream(new FileInputStream(zipFile),Charset.forName(Constant.SystemsPlatform.DEFAULT_ENCODING));
            //解压文件过程,具体实现
            ZipEntry zipEntry;
            byte[] b = new byte[1<<10];
            int n;
            String root=outDir.getAbsolutePath();
            while ((zipEntry=zipInputStream.getNextEntry())!=null){
                String entryName = zipEntry.getName();
                FileOutputStream fileoutputstream;
                File newFile = new File(entryName);
                String directory = newFile.getParent();
                //如果
                if (directory == null) {
                    if (newFile.isDirectory()) {
                        break;
                    }
                } else {
                    new File(root +File.separator+ directory).mkdirs();
                }

                if (!zipEntry.isDirectory()) {
                    System.out.println("File to be extracted....." + entryName);
                    fileoutputstream = new FileOutputStream(root +File.separator+ entryName);
                    while ((n = zipInputStream.read(b, 0, b.length)) > -1) {
                        fileoutputstream.write(b, 0, n);
                    }
                    fileoutputstream.close();
                }
                else{
                    new File(root +File.separator+ entryName).mkdirs();
                }
                zipInputStream.closeEntry();

            }
            //记录结束压缩时间
            long endMillis=System.currentTimeMillis();
            //转换中文注释乱码问题
            String comment="压缩总共花费时间:"+ DateUtil.millisToSimple(endMillis - beginMillis);
            System.out.println(comment);
            zipInputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 解压文件到某个位置(压缩中的文件与原来目录结构一致)
     * @param zipFilePath  --压缩文件路径
     * @param outDirPath   --解压位置路径
     */
    public static void unZipFile(String zipFilePath,String outDirPath){
        File zipFile=FileUtil.getFile(zipFilePath);
        File outDir=FileUtil.getFile(outDirPath);
        unZipFile(zipFile,outDir);
    }


    /**
     * 解压文件到某个位置(压缩中的文件与原来目录结构一致)
     * @param zipFilePath  --压缩文件路径
     * @param outDir   --解压位置
     */
    public static void unZipFile(String zipFilePath,File outDir){
        File zipFile=FileUtil.getFile(zipFilePath);
        unZipFile(zipFile,outDir);
    }

    /**
     * 解压文件到某个位置(压缩中的文件与原来目录结构一致)
     * @param zipFile  --压缩文件
     * @param outDirPath   --解压位置路径
     */
    public static void unZipFile(File zipFile,String outDirPath){
        File outDir=FileUtil.getFile(outDirPath);
        unZipFile(zipFile,outDir);
    }

    /**
     * gzip压缩文件
     * @param file --文件
     * @param gzipFile --gzip压缩后的文件
     */
    public static void gzipFile(File file,File gzipFile){
        try{
            if(file==null || !file.exists() || file.isDirectory() ){
                throw new FileNotFoundException("the file is null or not exists or is directory !");
            }
            //压缩输出流,并设置编码为当前系统编码,防止乱码
            GZIPOutputStream gzipOutputStream=new GZIPOutputStream(new FileOutputStream(gzipFile));
            FileInputStream fileInputStream=new FileInputStream(file);
            byte[] b=new byte[1<<10];
            int n;
            while ((n=fileInputStream.read(b))!=-1){
                gzipOutputStream.write(b,0,n);
            }
            fileInputStream.close();
            gzipOutputStream.finish();
            gzipOutputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * gzip压缩文件
     * @param file --文件
     * @param gzipFilePath --gzip压缩后的文件路径
     */
    public static void gzipFile(File file,String gzipFilePath){
        File gzipFile=FileUtil.getFile(gzipFilePath);
        gzipFile(file,gzipFile);
    }

    /**
     * gzip压缩文件
     * @param filePath --文件路径
     * @param gzipFile --gzip压缩后的文件
     */
    public static void gzipFile(String filePath,File gzipFile){
        File file=FileUtil.getFile(filePath);
        gzipFile(file,gzipFile);
    }

    /**
     * gzip压缩文件
     * @param filePath --文件路径
     * @param gzipFilePath --gzip压缩后的文件路径
     */
    public static void  gzipFile(String filePath,String gzipFilePath){
        File file=FileUtil.getFile(filePath);
        File gzipFile=FileUtil.getFile(gzipFilePath);
        gzipFile(file,gzipFile);
    }


    /**
     * gzip压缩文件(默认存放filePath路径,filePath文件名加gz后缀)
     * @param filePath --文件路径
     *
     */
    public static void  gzipFile(String filePath){
        File file=FileUtil.getFile(filePath);
        gzipFile(file);
    }


    /**
     * gzip压缩文件(默认存放file路径,file文件名加gz后缀)
     * @param file --文件路径
     *
     */
    public static void  gzipFile(File file){
        String inFileName= file.getName();
        //获取文件或文件夹所在的路径
        String dirPath=file.getParentFile().getAbsolutePath();
        //生成GZIP文件
        String gzipFilePath=dirPath+File.separator+inFileName+ Constant.File.FILE_DOT+Constant.File.EXTENSION_GZ;
        gzipFile(file,gzipFilePath);
    }


    /**
     * unGzip解压gzip文件
     * @param gzipFile  --gz文件
     * @param outFile   --解压后的文件
     */
    public static void unGzipFile(File gzipFile,File outFile){
        try{
            if(gzipFile==null || !gzipFile.exists() || gzipFile.isDirectory() ){
                throw new FileNotFoundException("the gzipFile is null or not exists or is directory !");
            }
            //压缩输出流,并设置编码为当前系统编码,防止乱码
            GZIPInputStream gzipInputStream=new GZIPInputStream(new FileInputStream(gzipFile));

            FileOutputStream fileOutputStream=new FileOutputStream(outFile);
            byte[] b=new byte[1<<10];
            int n;
            while ((n=gzipInputStream.read(b))!=-1){
                fileOutputStream.write(b,0,n);
            }
            gzipInputStream.close();
            fileOutputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     *  unGzip解压gzip文件
     * @param gzipFile  --gz文件
     * @param outFilePath    --解压后的文件路径
     */
    public static void unGzipFile(File gzipFile,String outFilePath){
        File outFile=FileUtil.getFile(outFilePath);
        unGzipFile(gzipFile,outFile);
    }

    /**
     * unGzip解压gzip文件
     * @param gzipFilePath --gz文件路径
     * @param outFile --解压后的文件
     */
    public static void unGzipFile(String gzipFilePath,File outFile){
        File gzipFile=FileUtil.getFile(gzipFilePath);
        unGzipFile(gzipFile,outFile);
    }

    /**
     * unGzip解压gzip文件
     * @param gzipFilePath --gz文件路径
     * @param outFilePath --解压后的文件路径
     */
    public static void unGzipFile(String gzipFilePath,String outFilePath){
        File gzipFile=FileUtil.getFile(gzipFilePath);
        File outFile=FileUtil.getFile(outFilePath);
        unGzipFile(gzipFile,outFile);
    }

    /**
     * unGzip解压gzip文件(默认文件名为gz文件除掉.gz)
     * @param gzipFile gz文件
     */
    public static void unGzipFile(File gzipFile){
        String inFileName= FileUtil.getFileName(gzipFile);
        //获取文件或文件夹所在的路径
        String dirPath=gzipFile.getParentFile().getAbsolutePath();
        //生成ZIP文件
        String outFilePath=dirPath+File.separator+inFileName+ Constant.File.FILE_DOT+Constant.File.EXTENSION_GZ;
        File outFile=FileUtil.getFile(outFilePath);
        unGzipFile(gzipFile, outFile);
    }

    /**
     * unGzip解压gzip文件(默认文件名为gz文件除掉.gz)
     * @param gzipFilePath  gz文件路径
     */
    public static void unGzipFile(String gzipFilePath){
        File gzipFile=FileUtil.getFile(gzipFilePath);
        unGzipFile(gzipFile);
    }

}


